package dict

import (
	"bytes"
	"fmt"
	"gitee.com/igolang/imoney/internal/app/system/entities"
	"gitee.com/igolang/imoney/internal/app/system/entities/constants"
	"gitee.com/igolang/imoney/internal/app/system/tools"
	commonEntities "gitee.com/igolang/imoney/internal/common/entities"
	"gitee.com/igolang/imoney/internal/common/httpResp"
	commonTools "gitee.com/igolang/imoney/internal/common/tools"
	"gitee.com/igolang/imoney/internal/core/client"
	"gitee.com/igolang/imoney/internal/models/dao"
	"gitee.com/igolang/imoney/internal/models/model"
	"gitee.com/igolang/pkg/xgorm"
	"gitee.com/igolang/pkg/xtime"
	"gitee.com/igolang/pkg/xutils"
	"github.com/gin-gonic/gin"
	"github.com/spf13/cast"
	"gorm.io/gen"
	"net/http"
	"time"
)

var DictType = &dictType{}

type dictType struct{}

func (s *dictType) List(req entities.DictPageListReq) (*commonEntities.ListResp, error) {
	conds := s.formatListConds(req)
	total, err := dao.SysDictType.Where(conds...).Count()
	if err != nil {
		return nil, err
	}
	result := &commonEntities.ListResp{
		Total: total,
		Rows:  make([]*model.SysDictType, 0),
	}
	if total == 0 {
		return result, nil
	}
	result.Rows, err = dao.SysDictType.Where(conds...).Limit(req.PageSize).Offset(req.Offset).Order(dao.SysDictType.DictID.Desc()).Find()
	if err != nil {
		return nil, err
	}
	return result, nil
}

func (s *dictType) Export(ctx *gin.Context) (b *bytes.Buffer, err error) {
	var req entities.DictPageListReq
	if err = ctx.ShouldBind(&req); err != nil {
		return nil, err
	}
	conds := s.formatListConds(req)
	rows, err := dao.SysDictType.Where(conds...).Rows()
	if err != nil {
		return nil, err
	}
	header := []string{"字典主键", "字典名称", "字典类型", "状态"}
	data := [][]string{header}
	dc := client.DB()
	commonStatusOptions, _ := Get("sys_normal_disable")
	for rows.Next() {
		row := &model.SysDictType{}
		if e := dc.ScanRows(rows, row); e == nil {
			data = append(data, []string{
				cast.ToString(row.DictID),
				row.DictName,
				row.DictType,
				LabelOptions(commonStatusOptions, row.Status),
			})
		}
	}
	fh := xutils.CreateExcelFileWithData(data)
	defer fh.Close()
	b, err = fh.WriteToBuffer()
	return
}

func (s *dictType) RefreshCache(ctx *gin.Context) error {
	rows, err := dao.SysDictType.Select(dao.SysDictType.DictType).Rows()
	if err != nil {
		return err
	}
	dc := client.DB()
	for rows.Next() {
		row := &model.SysDictType{}
		if e := dc.ScanRows(rows, row); e == nil {
			if row.Status != constants.OkStatus {
				DictData.cleanCache(row.DictType)
			} else {
				DictData.setCache(row.DictType)
			}
		}
	}

	return err
}

func (s *dictType) Save(ctx *gin.Context) (err error) {
	req := &model.SysDictType{}
	if err = ctx.ShouldBindJSON(req); err != nil {
		return
	}

	if req.DictType == "" || req.DictName == "" {
		return httpResp.ErrorCode(httpResp.ErrCodeInvalidParams)
	}

	if ctx.Request.Method == http.MethodPut && req.DictID == 0 {
		return httpResp.ErrorCode(httpResp.ErrCodeInvalidParams)
	}
	// 校验
	conds := make([]gen.Condition, 0)
	index := 0
	if req.DictID > 0 {
		conds = append(conds, dao.SysDictType.DictID.Neq(req.DictID))
		index = 1
	}
	conds = append(conds, dao.SysDictType.DictType.Eq(req.DictType))
	o, _ := dao.SysDictType.Where(conds...).Take()
	if o != nil {
		return fmt.Errorf(`字典标签'%s'已存在`, req.DictType)
	}
	conds[index] = dao.SysDictType.DictName.Eq(req.DictName)
	o, _ = dao.SysDictType.Where(conds...).Take()
	if o != nil {
		return fmt.Errorf(`字典名称'%s'已存在`, req.DictName)
	}

	if req.Status == "" {
		req.Status = constants.OkStatus
	}
	userInfo := tools.GetUserInfo(ctx)
	req.UpdateBy = userInfo.User.UserName
	req.UpdateTime = xtime.Time(time.Now())
	if req.DictID == 0 {
		req.CreateBy = userInfo.User.UserName
		req.CreateTime = xtime.Time(time.Now())
		err = dao.SysDictType.Create(req)
		if err == nil && req.Status == constants.OkStatus {
			DictData.setCache(req.DictType)
		}
	}
	row, err := dao.SysDictType.Where(dao.SysDictType.DictID.Eq(req.DictID)).Take()
	if err != nil {
		return err
	}
	oldType := row.DictType
	row.DictType = req.DictType
	row.UpdateTime = req.UpdateTime
	row.UpdateBy = req.UpdateBy
	row.Remark = req.Remark
	row.Status = req.Status
	row.DictName = req.DictName
	data := xgorm.ModelToMap(row)
	_, err = dao.SysDictType.Where(dao.SysDictType.DictID.Eq(req.DictID)).Updates(data)
	if err == nil {
		if req.DictType != oldType {
			dao.SysDictDatum.Where(dao.SysDictDatum.DictType.Eq(row.DictType)).Update(dao.SysDictDatum.DictType, req.DictType)
		}
		DictData.cleanCache(row.DictType)
		if req.Status == constants.OkStatus {
			DictData.setCache(req.DictType)
		}
	}
	return
}

func (s *dictType) Delete(ctx *gin.Context) (err error) {
	ids := commonTools.String2Int64s(ctx.Param("ids"))
	if len(ids) == 0 {
		return httpResp.ErrorCode(httpResp.ErrCodeInvalidParams)
	}
	// 检验是否已分配
	rows, err := dao.SysDictType.Select(dao.SysDictType.DictType, dao.SysDictType.DictName).Where(dao.SysDictType.DictID.In(ids...)).Find()
	if err != nil {
		return err
	}
	if len(rows) == 0 {
		return nil
	}
	for _, v := range rows {
		if count, _ := dao.SysDictDatum.Where(dao.SysDictDatum.DictType.Eq(v.DictType)).Count(); count > 0 {
			return httpResp.ErrWarning("%s已分配，不能删除", v.DictName)
		}
	}
	_, err = dao.SysDictType.Where(dao.SysDictType.DictID.In(ids...)).Delete()
	if err == nil {
		for _, v := range rows {
			DictData.cleanCache(v.DictType)
		}
	}
	return
}

func (s *dictType) formatListConds(req entities.DictPageListReq) []gen.Condition {
	conds := make([]gen.Condition, 0)
	req.Page()
	if req.DictType != "" {
		conds = append(conds, dao.SysDictType.DictType.Like(`%`+req.DictType+`%`))
	}

	if req.DictName != "" {
		conds = append(conds, dao.SysDictType.DictName.Like(`%`+req.DictName+`%`))
	}

	if req.Status != "" {
		conds = append(conds, dao.SysDictType.Status.Eq(req.Status))
	}

	if !req.BT.IsZero() && !req.ET.IsZero() {
		conds = append(conds, dao.SysDictType.CreateTime.Gte(req.BT), dao.SysDictType.CreateTime.Lte(req.ET))
	}

	return conds
}
